// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/events/keycodes/keyboard_code_conversion_xkb.h"

#include "build/build_config.h"
#include "ui/events/keycodes/dom/dom_key.h"
#include "ui/events/keycodes/keyboard_code_conversion.h"

#ifndef XK_dead_greek
#define XK_dead_greek 0xfe8c
#endif

namespace ui {

DomKey NonPrintableXKeySymToDomKey(xkb_keysym_t keysym)
{
    switch (keysym) {
    case XKB_KEY_BackSpace:
        return DomKey::BACKSPACE;
    case XKB_KEY_Tab:
    case XKB_KEY_KP_Tab:
    case XKB_KEY_ISO_Left_Tab:
        return DomKey::TAB;
    case XKB_KEY_Clear:
    case XKB_KEY_KP_Begin:
    case XKB_KEY_XF86Clear:
        return DomKey::CLEAR;
    case XKB_KEY_Return:
    case XKB_KEY_KP_Enter:
        return DomKey::ENTER;
    case XKB_KEY_Linefeed:
        return DomKey::ENTER;
    case XKB_KEY_Pause:
        return DomKey::PAUSE;
    case XKB_KEY_Scroll_Lock:
        return DomKey::SCROLL_LOCK;
    case XKB_KEY_Escape:
        return DomKey::ESCAPE;
    case XKB_KEY_Multi_key:
        return DomKey::COMPOSE;
    case XKB_KEY_Kanji:
        return DomKey::KANJI_MODE;
    case XKB_KEY_Muhenkan:
        return DomKey::NON_CONVERT;
    case XKB_KEY_Henkan_Mode:
        return DomKey::CONVERT;
    case XKB_KEY_Romaji:
        return DomKey::ROMAJI;
    case XKB_KEY_Hiragana:
        return DomKey::HIRAGANA;
    case XKB_KEY_Katakana:
        return DomKey::KATAKANA;
    case XKB_KEY_Hiragana_Katakana:
        return DomKey::HIRAGANA_KATAKANA;
    case XKB_KEY_Zenkaku:
        return DomKey::ZENKAKU;
    case XKB_KEY_Hankaku:
        return DomKey::HANKAKU;
    case XKB_KEY_Zenkaku_Hankaku:
        return DomKey::ZENKAKU_HANKAKU;
    case XKB_KEY_Kana_Lock:
        return DomKey::KANA_MODE;
    case XKB_KEY_Eisu_Shift:
    case XKB_KEY_Eisu_toggle:
        return DomKey::EISU;
    case XKB_KEY_Hangul:
        return DomKey::HANGUL_MODE;
    case XKB_KEY_Hangul_Hanja:
        return DomKey::HANJA_MODE;
    case XKB_KEY_Codeinput:
        return DomKey::CODE_INPUT;
    case XKB_KEY_SingleCandidate:
        return DomKey::SINGLE_CANDIDATE;
    case XKB_KEY_MultipleCandidate:
        return DomKey::ALL_CANDIDATES;
    case XKB_KEY_PreviousCandidate:
        return DomKey::PREVIOUS_CANDIDATE;
    case XKB_KEY_Home:
    case XKB_KEY_KP_Home:
        return DomKey::HOME;
    case XKB_KEY_Left:
    case XKB_KEY_KP_Left:
        return DomKey::ARROW_LEFT;
    case XKB_KEY_Up:
    case XKB_KEY_KP_Up:
        return DomKey::ARROW_UP;
    case XKB_KEY_Right:
    case XKB_KEY_KP_Right:
        return DomKey::ARROW_RIGHT;
    case XKB_KEY_Down:
    case XKB_KEY_KP_Down:
        return DomKey::ARROW_DOWN;
    case XKB_KEY_Prior:
    case XKB_KEY_KP_Prior:
        return DomKey::PAGE_UP;
    case XKB_KEY_Next:
    case XKB_KEY_KP_Next:
    case XKB_KEY_XF86ScrollDown:
        return DomKey::PAGE_DOWN;
    case XKB_KEY_End:
    case XKB_KEY_KP_End:
    case XKB_KEY_XF86ScrollUp:
        return DomKey::END;
    case XKB_KEY_Select:
        return DomKey::SELECT;
    case XKB_KEY_Print:
        return DomKey::PRINT;
    case XKB_KEY_Execute:
        return DomKey::EXECUTE;
    case XKB_KEY_Insert:
    case XKB_KEY_KP_Insert:
        return DomKey::INSERT;
    case XKB_KEY_Undo:
        return DomKey::UNDO;
    case XKB_KEY_Redo:
        return DomKey::REDO;
    case XKB_KEY_Menu:
        return DomKey::CONTEXT_MENU;
    case XKB_KEY_Find:
        return DomKey::FIND;
    case XKB_KEY_Cancel:
        return DomKey::CANCEL;
    case XKB_KEY_Help:
        return DomKey::HELP;
    case XKB_KEY_Break:
    case XKB_KEY_3270_Attn:
        return DomKey::ATTN;
    case XKB_KEY_Mode_switch:
        return DomKey::MODE_CHANGE;
    case XKB_KEY_Num_Lock:
        return DomKey::NUM_LOCK;
    case XKB_KEY_F1:
    case XKB_KEY_KP_F1:
        return DomKey::F1;
    case XKB_KEY_F2:
    case XKB_KEY_KP_F2:
        return DomKey::F2;
    case XKB_KEY_F3:
    case XKB_KEY_KP_F3:
        return DomKey::F3;
    case XKB_KEY_F4:
    case XKB_KEY_KP_F4:
        return DomKey::F4;
    case XKB_KEY_F5:
        return DomKey::F5;
    case XKB_KEY_F6:
        return DomKey::F6;
    case XKB_KEY_F7:
        return DomKey::F7;
    case XKB_KEY_F8:
        return DomKey::F8;
    case XKB_KEY_F9:
        return DomKey::F9;
    case XKB_KEY_F10:
        return DomKey::F10;
    case XKB_KEY_F11:
        return DomKey::F11;
    case XKB_KEY_F12:
        return DomKey::F12;
    case XKB_KEY_XF86Tools: // XKB 'inet' mapping of F13
    case XKB_KEY_F13:
        return DomKey::F13;
    case XKB_KEY_F14:
    case XKB_KEY_XF86Launch5: // XKB 'inet' mapping of F14
        return DomKey::F14;
    case XKB_KEY_F15:
    case XKB_KEY_XF86Launch6: // XKB 'inet' mapping of F15
        return DomKey::F15;
    case XKB_KEY_F16:
    case XKB_KEY_XF86Launch7: // XKB 'inet' mapping of F16
        return DomKey::F16;
    case XKB_KEY_F17:
    case XKB_KEY_XF86Launch8: // XKB 'inet' mapping of F17
        return DomKey::F17;
    case XKB_KEY_F18:
    case XKB_KEY_XF86Launch9: // XKB 'inet' mapping of F18
        return DomKey::F18;
    case XKB_KEY_F19:
        return DomKey::F19;
    case XKB_KEY_F20:
        return DomKey::F20;
    case XKB_KEY_F21:
        return DomKey::F21;
    case XKB_KEY_F22:
        return DomKey::F22;
    case XKB_KEY_F23:
        return DomKey::F23;
    case XKB_KEY_F24:
        return DomKey::F24;
    case XKB_KEY_Shift_L:
    case XKB_KEY_Shift_R:
        return DomKey::SHIFT;
    case XKB_KEY_Control_L:
    case XKB_KEY_Control_R:
        return DomKey::CONTROL;
    case XKB_KEY_Caps_Lock:
        return DomKey::CAPS_LOCK;
#if defined(OS_CHROMEOS)
    case XKB_KEY_Meta_L:
    case XKB_KEY_Meta_R:
    case XKB_KEY_Alt_L:
    case XKB_KEY_Alt_R:
        // The Shift+Alt generates a KeySym for the Meta key. On ChromeOS the Meta
        // key is not used and we should still get the Alt key. crbug.com/541468.
        return DomKey::ALT;
#else
    case XKB_KEY_Meta_L:
    case XKB_KEY_Meta_R:
        return DomKey::META;
    case XKB_KEY_Alt_L:
    case XKB_KEY_Alt_R:
        return DomKey::ALT;
#endif // defined(OS_CHROMEOS)
    case XKB_KEY_Super_L:
    case XKB_KEY_Super_R:
        return DomKey::META;
    case XKB_KEY_Hyper_L:
    case XKB_KEY_Hyper_R:
        return DomKey::HYPER;
    case XKB_KEY_Delete:
        return DomKey::DEL;
    case XKB_KEY_SunProps:
        return DomKey::PROPS;
    case XKB_KEY_XF86Next_VMode:
        return DomKey::VIDEO_MODE_NEXT;
    case XKB_KEY_XF86MonBrightnessUp:
        return DomKey::BRIGHTNESS_UP;
    case XKB_KEY_XF86MonBrightnessDown:
        return DomKey::BRIGHTNESS_DOWN;
    case XKB_KEY_XF86Standby:
    case XKB_KEY_XF86Sleep:
    case XKB_KEY_XF86Suspend:
        return DomKey::STANDBY;
    case XKB_KEY_XF86AudioLowerVolume:
        return DomKey::AUDIO_VOLUME_DOWN;
    case XKB_KEY_XF86AudioMute:
        return DomKey::AUDIO_VOLUME_MUTE;
    case XKB_KEY_XF86AudioRaiseVolume:
        return DomKey::AUDIO_VOLUME_UP;
    case XKB_KEY_XF86AudioPlay:
        return DomKey::MEDIA_PLAY;
    case XKB_KEY_XF86AudioStop:
        return DomKey::MEDIA_STOP;
    case XKB_KEY_XF86AudioPrev:
        return DomKey::MEDIA_TRACK_PREVIOUS;
    case XKB_KEY_XF86AudioNext:
        return DomKey::MEDIA_TRACK_NEXT;
    case XKB_KEY_XF86HomePage:
        return DomKey::BROWSER_HOME;
    case XKB_KEY_XF86Mail:
        return DomKey::LAUNCH_MAIL;
    case XKB_KEY_XF86Search:
        return DomKey::BROWSER_SEARCH;
    case XKB_KEY_XF86AudioRecord:
        return DomKey::MEDIA_RECORD;
    case XKB_KEY_XF86Calculator:
        return DomKey::LAUNCH_CALCULATOR;
    case XKB_KEY_XF86Calendar:
        return DomKey::LAUNCH_CALENDAR;
    case XKB_KEY_XF86Back:
        return DomKey::BROWSER_BACK;
    case XKB_KEY_XF86Forward:
        return DomKey::BROWSER_FORWARD;
    case XKB_KEY_XF86Stop:
        return DomKey::BROWSER_STOP;
    case XKB_KEY_XF86Refresh:
    case XKB_KEY_XF86Reload:
        return DomKey::BROWSER_REFRESH;
    case XKB_KEY_XF86PowerOff:
        return DomKey::POWER_OFF;
    case XKB_KEY_XF86WakeUp:
        return DomKey::WAKE_UP;
    case XKB_KEY_XF86Eject:
        return DomKey::EJECT;
    case XKB_KEY_XF86ScreenSaver:
        return DomKey::LAUNCH_SCREEN_SAVER;
    case XKB_KEY_XF86WWW:
        return DomKey::LAUNCH_WEB_BROWSER;
    case XKB_KEY_XF86Favorites:
        return DomKey::BROWSER_FAVORITES;
    case XKB_KEY_XF86AudioPause:
        return DomKey::MEDIA_PAUSE;
    case XKB_KEY_XF86AudioMedia:
    case XKB_KEY_XF86Music:
        return DomKey::LAUNCH_MUSIC_PLAYER;
    case XKB_KEY_XF86MyComputer:
    case XKB_KEY_XF86Explorer:
        return DomKey::LAUNCH_MY_COMPUTER;
    case XKB_KEY_XF86AudioRewind:
        return DomKey::MEDIA_REWIND;
    case XKB_KEY_XF86CD:
    case XKB_KEY_XF86Video:
        return DomKey::LAUNCH_MEDIA_PLAYER;
    case XKB_KEY_XF86Close:
        return DomKey::CLOSE;
    case XKB_KEY_XF86Copy:
    case XKB_KEY_SunCopy:
        return DomKey::COPY;
    case XKB_KEY_XF86Cut:
    case XKB_KEY_SunCut:
        return DomKey::CUT;
    case XKB_KEY_XF86Display:
        return DomKey::DISPLAY_SWAP;
    case XKB_KEY_XF86Excel:
        return DomKey::LAUNCH_SPREADSHEET;
    case XKB_KEY_XF86LogOff:
        return DomKey::LOG_OFF;
    case XKB_KEY_XF86New:
        return DomKey::NEW;
    case XKB_KEY_XF86Open:
    case XKB_KEY_SunOpen:
        return DomKey::OPEN;
    case XKB_KEY_XF86Paste:
    case XKB_KEY_SunPaste:
        return DomKey::PASTE;
    case XKB_KEY_XF86Reply:
        return DomKey::MAIL_REPLY;
    case XKB_KEY_XF86Save:
        return DomKey::SAVE;
    case XKB_KEY_XF86Send:
        return DomKey::MAIL_SEND;
    case XKB_KEY_XF86Spell:
        return DomKey::SPELL_CHECK;
    case XKB_KEY_XF86SplitScreen:
        return DomKey::SPLIT_SCREEN_TOGGLE;
    case XKB_KEY_XF86Word:
    case XKB_KEY_XF86OfficeHome:
        return DomKey::LAUNCH_WORD_PROCESSOR;
    case XKB_KEY_XF86ZoomIn:
        return DomKey::ZOOM_IN;
    case XKB_KEY_XF86ZoomOut:
        return DomKey::ZOOM_OUT;
    case XKB_KEY_XF86WebCam:
        return DomKey::LAUNCH_WEB_CAM;
    case XKB_KEY_XF86MailForward:
        return DomKey::MAIL_FORWARD;
    case XKB_KEY_XF86AudioForward:
        return DomKey::MEDIA_FAST_FORWARD;
    case XKB_KEY_XF86AudioRandomPlay:
        return DomKey::RANDOM_TOGGLE;
    case XKB_KEY_XF86Subtitle:
        return DomKey::SUBTITLE;
    case XKB_KEY_XF86Hibernate:
        return DomKey::HIBERNATE;
    case XKB_KEY_3270_EraseEOF:
        return DomKey::ERASE_EOF;
    case XKB_KEY_3270_Play:
        return DomKey::PLAY;
    case XKB_KEY_3270_ExSelect:
        return DomKey::EX_SEL;
    case XKB_KEY_3270_CursorSelect:
        return DomKey::CR_SEL;
    case XKB_KEY_3270_PrintScreen:
        return DomKey::PRINT_SCREEN;
    case XKB_KEY_ISO_Level3_Shift:
        return DomKey::ALT_GRAPH;
    case XKB_KEY_ISO_Level3_Latch:
        return DomKey::ALT_GRAPH_LATCH;
    case XKB_KEY_ISO_Level5_Shift:
        return DomKey::SHIFT_LEVEL5;
    case XKB_KEY_ISO_Next_Group:
        return DomKey::GROUP_NEXT;
    case XKB_KEY_ISO_Prev_Group:
        return DomKey::GROUP_PREVIOUS;
    case XKB_KEY_ISO_First_Group:
        return DomKey::GROUP_FIRST;
    case XKB_KEY_ISO_Last_Group:
        return DomKey::GROUP_LAST;
    case XKB_KEY_dead_grave:
        // combining grave accent
        return DomKey::DeadKeyFromCombiningCharacter(0x0300);
    case XKB_KEY_dead_acute:
        // combining acute accent
        return DomKey::DeadKeyFromCombiningCharacter(0x0301);
    case XKB_KEY_dead_circumflex:
        // combining circumflex accent
        return DomKey::DeadKeyFromCombiningCharacter(0x0302);
    case XKB_KEY_dead_tilde:
        // combining tilde
        return DomKey::DeadKeyFromCombiningCharacter(0x0303);
    case XKB_KEY_dead_macron:
        // combining macron
        return DomKey::DeadKeyFromCombiningCharacter(0x0304);
    case XKB_KEY_dead_breve:
        // combining breve
        return DomKey::DeadKeyFromCombiningCharacter(0x0306);
    case XKB_KEY_dead_abovedot:
        // combining dot above
        return DomKey::DeadKeyFromCombiningCharacter(0x0307);
    case XKB_KEY_dead_diaeresis:
        // combining diaeresis
        return DomKey::DeadKeyFromCombiningCharacter(0x0308);
    case XKB_KEY_dead_abovering:
        // combining ring above
        return DomKey::DeadKeyFromCombiningCharacter(0x030A);
    case XKB_KEY_dead_doubleacute:
        // combining double acute accent
        return DomKey::DeadKeyFromCombiningCharacter(0x030B);
    case XKB_KEY_dead_caron:
        // combining caron
        return DomKey::DeadKeyFromCombiningCharacter(0x030C);
    case XKB_KEY_dead_cedilla:
        // combining cedilla
        return DomKey::DeadKeyFromCombiningCharacter(0x0327);
    case XKB_KEY_dead_ogonek:
        // combining ogonek
        return DomKey::DeadKeyFromCombiningCharacter(0x0328);
    case XKB_KEY_dead_iota:
        // combining greek ypogegrammeni
        return DomKey::DeadKeyFromCombiningCharacter(0x0345);
    case XKB_KEY_dead_voiced_sound:
        // combining voiced sound mark
        return DomKey::DeadKeyFromCombiningCharacter(0x3099);
    case XKB_KEY_dead_semivoiced_sound:
        // combining semi-voiced sound mark
        return DomKey::DeadKeyFromCombiningCharacter(0x309A);
    case XKB_KEY_dead_belowdot:
        // combining dot below
        return DomKey::DeadKeyFromCombiningCharacter(0x0323);
    case XKB_KEY_dead_hook:
        // combining hook above
        return DomKey::DeadKeyFromCombiningCharacter(0x0309);
    case XKB_KEY_dead_horn:
        // combining horn
        return DomKey::DeadKeyFromCombiningCharacter(0x031B);
    case XKB_KEY_dead_stroke:
        // combining long solidus overlay
        return DomKey::DeadKeyFromCombiningCharacter(0x0338);
    case XKB_KEY_dead_abovecomma:
        // combining comma above
        return DomKey::DeadKeyFromCombiningCharacter(0x0313);
    case XKB_KEY_dead_abovereversedcomma:
        // combining reversed comma above
        return DomKey::DeadKeyFromCombiningCharacter(0x0314);
    case XKB_KEY_dead_doublegrave:
        // combining double grave accent
        return DomKey::DeadKeyFromCombiningCharacter(0x030F);
    case XKB_KEY_dead_belowring:
        // combining ring below
        return DomKey::DeadKeyFromCombiningCharacter(0x0325);
    case XKB_KEY_dead_belowmacron:
        // combining macron below
        return DomKey::DeadKeyFromCombiningCharacter(0x0331);
    case XKB_KEY_dead_belowcircumflex:
        // combining circumflex accent below
        return DomKey::DeadKeyFromCombiningCharacter(0x032D);
    case XKB_KEY_dead_belowtilde:
        // combining tilde below
        return DomKey::DeadKeyFromCombiningCharacter(0x0330);
    case XKB_KEY_dead_belowbreve:
        // combining breve below
        return DomKey::DeadKeyFromCombiningCharacter(0x032E);
    case XKB_KEY_dead_belowdiaeresis:
        // combining diaeresis below
        return DomKey::DeadKeyFromCombiningCharacter(0x0324);
    case XKB_KEY_dead_invertedbreve:
        // combining inverted breve
        return DomKey::DeadKeyFromCombiningCharacter(0x0311);
    case XKB_KEY_dead_belowcomma:
        // combining comma below
        return DomKey::DeadKeyFromCombiningCharacter(0x0326);
    case XKB_KEY_dead_currency:
        // currency sign
        return DomKey::DeadKeyFromCombiningCharacter(0x00A4);
    case XKB_KEY_dead_greek:
        // greek question mark
        return DomKey::DeadKeyFromCombiningCharacter(0x037E);
    default:
        return DomKey::NONE;
    }
}

DomKey XKeySymToDomKey(xkb_keysym_t keysym, base::char16 character)
{
    DomKey dom_key = NonPrintableXKeySymToDomKey(keysym);
    if (dom_key != DomKey::NONE)
        return dom_key;
    return DomKey::FromCharacter(character);
}

} // namespace ui
